﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////


#pragma once

#include "IGeometry.h"
#include "Vector3d.h"
#include "GeometryErrorCode.h"
#include "ICurve3d.h"

namespace gcmp
{
    class IBody;

    /// \brief 多段线（三维）
    ///
    /// 由首尾相连的三维曲线组成，可以不封闭
    /// 简单的多段线仅有直线组成，复杂的多段线可以由复合曲线组成（比如直线/圆弧/样条曲线等）
    class IPolyCurve3d : public IGeometry
    {
        DEFINE_CAST_DERIVED(gcmp::IPolyCurve3d, gcmp::IGeometry);
    public:
        /// \brief  创建一个空的三维多段线(不包含任何线)
        /// \return  三维空多段线(不包含任何线)
        GCMP_GEOMETRY_INTERFACE_EXPORT static OwnerPtr<IPolyCurve3d> Create();

        /// \brief  创建一个多段线，根据点集创建首尾相接的直线组成的多段线
        /// \param[in] profilePoints    顺序点
        /// \return  三维直线组成的多段线
        GCMP_GEOMETRY_INTERFACE_EXPORT static OwnerPtr<IPolyCurve3d> Create(const std::vector<Vector3d>& profilePoints);

        /// \brief  创建一个多段线
        /// \param[in]  profileCurve3ds    顺序线段
        /// \return  多段线
        GCMP_GEOMETRY_INTERFACE_EXPORT static OwnerPtr<IPolyCurve3d> Create(const std::vector< OwnerPtr<ICurve3d> >& profileCurve3ds);

        /// \brief  由线框体创建一组三维多段线
        /// \param[in]  pWireBody    Wire类型的体对象
        /// \param[out] opPolyCurve3ds  创建的一组三维多段线
        /// \return  错误码
        GCMP_GEOMETRY_INTERFACE_EXPORT static GeometryErrorCode Create(const IBody* pWireBody, std::vector<OwnerPtr<IPolyCurve3d>>& opPolyCurve3ds);

    public:
        /// \brief  获取多段线中曲线的数量
        /// \brief  曲线的数量
        virtual int GetCurveCount() const = 0;

        /// \brief  获取指定索引处的三维曲线
        /// \param  index    索引
        /// \return  索引在三维边链表范围内返回三维边，否则返回空
        virtual const ICurve3d* GetCurveByIndex(int index) const = 0;

        /// \brief   按顺序获取多段线中所有的曲线
        /// \param  curve3dlist 多段线中所有的曲线
        /// \return  成功返回true,否则返回false(默认返回true)
        virtual bool GetAllCurves(std::vector<const ICurve3d*>& curve3dlist) const = 0;

        /// \brief  将三维曲线添加到多段线中
        /// \param  opCurve3d 三维曲线
        /// \return  成功返回true,否则返回false(默认返回true)
        virtual bool AddCurve(OwnerPtr<ICurve3d> opCurve3d) = 0;

        /// \brief  将三维曲线在指定位置插入到多段线中
        /// \param[in]  nInsertPos 指定索引，从0开始，0表示插入后作为多段线的第一条曲线；
        ///                        最大索引为多段线中曲线的数量值，插入后作为最后一条曲线
        /// \param[in]  opCurve3d 三维曲线
        /// \return  成功返回true,否则返回false
        virtual bool InsertCurve(int nInsertPos, OwnerPtr<ICurve3d> opCurve3d) = 0;

        /// \brief  删除多段线指定索引
        /// \param[in]  nIndex 指定索引，从0开始，0表示删除第一条曲线；
        ///                    最大索引为多段线中曲线的数量值 - 1，表示删除最后一条曲线
        /// \return  成功返回true,否则返回false
        virtual bool DeleteCurve(int nIndex) = 0;

        /// \brief  获取三维多段线的终点,确保含有曲线
        /// \param[out]  endPoint 终点
        /// \return 成功返回true,否则返回false
        virtual bool GetEndPoint(Vector3d& endPoint) const = 0;

        /// \brief  获取三维多段线终点的切向,确保含有曲线
        /// \param[out]  endTangent 终点的切向
        /// \return 成功返回true,否则返回false
        virtual bool GetEndTangent(Vector3d& endTangent) const = 0;

        /// \brief  多段线中所有三维边是否首尾相连（不要求最后一条边与第一条边相连），多段线为空时返回false
        /// \return  首尾相连返回true,否则返回false
        virtual bool IsConnected() const = 0;

        /// \brief  向多段线中添加一条三维曲线，使整个多段线闭合
        /// \param[in]  isSmooth  true采用Bezier曲线闭合, false 采用直线闭合
        /// \return  是否添加闭合曲线成功,成功返回true,否则返回false
        virtual bool SetClosed(bool isSmooth) = 0;

        /// \brief  判断多段线中所有的边首尾相连且环封闭（以curve3dList自身的距离容差m_DistEpsilon作为是否首尾相连且封闭的判断依据）
        /// \return  true: 首尾相连且封闭，  false: 不封闭或边首尾不相连
        virtual bool IsClosed() const = 0;

        /// \brief  把此三维多段线中的所有边反向
        /// \return   成功返回true,否则返回false(默认返回true)
        virtual bool Reverse() = 0;

        /// \brief  设置距离容差
        /// \param distanceEpsilon 距离容差
        /// \return  成功返回True，失败返回False
        virtual bool SetDistEpsilon(double dDistEpsilon) = 0;

        /// \brief  获取距离容差
        /// \return  距离容差
        virtual double GetDistEpsilon() const = 0;

        /// \brief  获取指定索引处的三维曲线（拷贝实现），暂时产品端还在使用，等后面产品端替换新的接口再废弃
        /// \param index    索引
        /// \return  索引在三维边链表范围内返回拷贝后的三维边，否则返回空
        virtual OwnerPtr<ICurve3d> GetCurve(int index) const = 0;

        /// \brief   按顺序获取多段线中所有的曲线（拷贝实现），暂时产品端还在使用，等后面产品端替换新的接口再废弃
        /// \param  curve3dlist 多段线中所有的曲线
        /// \return  成功返回true,否则返回false(默认返回true)
        virtual bool GetAllCurves(std::vector<OwnerPtr<ICurve3d>>& curve3dlist) const = 0;

        /// \brief  将三维直线添加到多段线中
        /// \param[in]  startPt  直线起点
        /// \param[in]  endPt  直线终点
        /// \param[in]  isSmooth  是否平滑连接，当三维多段线为空时，isSmooth失效；
        ///                       当isSmooth有效并为true时，仅使用终点endPt，以多段线最后一条曲线的终点为起点，并与之相切，
        ///                       当endPt不在切线上，投影到切线上的点为实际直线终点
        /// \return  成功返回true,否则返回false
        virtual bool AddLine(const Vector3d& startPt, const Vector3d& endPt, bool isSmooth = false) = 0;

        /// \brief  向多段线中添加一条三维线段并倒圆角，该线段由多段线中最后一条曲线的终止点指向新指定的三维点，
        ///         圆弧过渡可达到一阶连续，最后一条曲线必须为线段才可倒圆角，
        ///         接口暂时未被使用，后面根据需要再放开，目前仅内部测试命令使用。
        /// \param[in]  pt  新指定的三维点，该点不可位于多段线中的最后一条线段或其延长线上
        /// \param[in]  filletRadius  过渡半径
        /// \return  是否添加圆弧过渡成功,成功返回true,否则返回false
        GCMP_DEPRECATED_API(2023 / 12 / 01) virtual bool AddLineFillet(const Vector3d& pt, double filletRadius) = 0;

        /// \brief  向多段线中添加一条三维线段并倒直角，该线段由多段线中最后一条曲线的终止点指向新指定的三维点，
        ///         最后一条曲线必须为线段才可倒直角，接口暂时未被使用，后面根据需要再放开，目前仅内部测试命令使用。
        /// \param[in]  pt  新指定的三维点，该点不可位于多段线中的最后一条线段或其延长线上
        /// \param[in]  chamferLenth1  多段线中最后一条线段上的偏移距离（沿直线从端点到交点的距离）
        /// \param[in]  chamferLenth2  新创建线段上的偏移距离（沿直线从端点到交点的距离）
        /// \return  是否添加倒直角成功,成功返回true,否则返回false
        GCMP_DEPRECATED_API(2023 / 12 / 01) virtual bool AddLineChamfer(const Vector3d& pt, double chamferLenth1, double chamferLenth2) = 0;

        /// \brief 向多段线中添加一条三点圆弧曲线（起点、参考点、终点），接口暂时未被使用，后面根据需要再放开，目前仅内部测试命令使用
        /// isSmooth为true，arcPoints[1]（圆弧参考点）无效；isSmooth为false，arcPoints[1]（圆弧参考点）有效；
        /// 添加第一条曲线时isSmooth无效(按false处理)，平滑连接时使用多段线终点以及终点切向，接口内部计算
        /// useRadius为true，radius有效；useRadius为false，radius无效；
        /// useAngle为true，angle有效；useAngle为false，angle无效；
        /// 1、三点arcPoints（isSmooth:false;useRadius:false;useAngle:false）
        ///    输入参数为起点、参考点、终点，需保证三点不共线，否则返回失败；
        /// 2、三点arcPoints+平滑（isSmooth:true;useRadius:false;useAngle:false）
        ///    参考点这时不用，使用起点和终点（两点连线的垂直平分线和切线的垂线的交点确定圆心），
        ///    需保证起点与终点的连线与切线不共线，否则返回失败；终点可确定圆弧的顺逆时针和实际终位置；
        /// 3、三点arcPoints+半径（isSmooth:false;useRadius:true;useAngle:false）
        ///    需保证三点arcPoints不共线，否则返回失败，起点和参考点以及半径可以确定圆心位置；
        ///    终点可确定圆弧的顺逆时针和相对终止位置，终点与圆心连线，该连线（延伸线）与圆弧的交点即为圆弧实际终点
        /// 4、三点arcPoints+圆心角（isSmooth:false;useRadius:false;useAngle:true）
        ///    起点、参考点、终点可确定圆心，需保证三点不共线，否则返回失败；
        ///    终点可确定圆弧的顺逆时针和相对终止位置，按照所输入的角度，从起点开始，截取圆心角所对应的圆弧
        /// 5、三点arcPoints+平滑+半径（isSmooth:true;useRadius:true;useAngle:false）
        ///    参考点这时不用，使用起点和切线垂直方向以及半径可以定位圆心（终点那一侧）；
        ///    需保证起点与终点的连线与切线不共线，否则返回失败；
        ///    终点可确定圆弧的顺逆时针和相对终止位置，终点与圆心连线，该连线（延伸线）与圆弧的交点即为圆弧实际终点
        /// 6、三点arcPoints+平滑+圆心角（isSmooth:true;useRadius:false;useAngle:true）
        ///    参考点这时不用，使用起点/终点连线的垂直平分线和切线垂直方向的交点以可以定位圆心；
        ///    需保证起点与终点的连线与切线不共线，否则返失败；
        ///    终点可确定圆弧的顺逆时针和相对终止位置，按照所输入的角度，从起点开始，截取圆心角所对应的圆弧；
        /// 7、三点arcPoints+半径+圆心角（isSmooth:false;useRadius:true;useAngle:true）
        ///    需保证三点arcPoints不共线，否则返回失败，起点和参考点以及半径可以确定圆心位置；
        ///    终点可确定圆弧的顺逆时针；按照所输入的角度，从起点开始，截取圆心角所对应的圆弧；
        /// 8、三点arcPoints+平滑+半径+圆心角（isSmooth:true;useRadius:true;useAngle:true）
        ///    参考点这时不用，需保证起点与终点的连线与切线不共线，否则返回失败；
        ///    终点主要用于定位圆弧所在的平面，按照所输入的半径和角度，从起点开始，截取圆心角所对应的圆弧；
        /// \param[in]  arcPoints  输入为三点，分别为起点、参考点、终点
        /// \param[in]  isSmooth  是否平滑连接
        /// \param[in]  useRadius  是否使用半径
        /// \param[in]  radius  圆弧半径，useRadius为true时使用（使用时半径需要大于0）
        /// \param[in]  useAngle  是否使用角度
        /// \param[in]  angle  圆弧角度，单位弧度，useAngle为true时使用（使用时需要在(0,2PI]区间内）
        /// \return  是否添加三点圆弧曲线成功,成功返回true,否则返回false
        GCMP_DEPRECATED_API(2023 / 12 / 01) virtual bool AddThreePointsArc(const std::vector<Vector3d>& arcPoints, bool isSmooth,
            bool useRadius, double radius, bool useAngle, double angle) = 0;

        /// \brief 向多段线中添加一条圆心端点圆弧曲线（起点、圆心、终点），接口暂时未被使用，后面根据需要再放开，目前仅内部测试命令使用
        /// isSmooth为true，isCounterClock无效；isSmooth为false，isCounterClock有效；
        /// 添加第一条曲线时isSmooth无效(按false处理)，平滑连接时使用多段线终点以及终点切向，接口内部计算
        /// useRadius为true，radius有效；useRadius为false，radius无效；
        /// useAngle为true，angle有效；useAngle为false，angle无效；
        /// 顺逆时针规则，（起点 - 圆心）方向叉乘（终点 - 圆心）方向为Z轴正向，从Z轴正向延-Z看的顺逆时针
        /// 1、圆心与两点圆弧arcPoints（isSmooth:false;useRadius:false;useAngle:false）
        ///    输入参数为起点、圆心（实际）、终点（需指定实际位置）、是否逆时针，需保证三点不共线，否则返失败；
        /// 2、圆心与两点圆弧arcPoints+平滑（isSmooth:true;useRadius:false;useAngle:false）
        ///    isCounterClock失效，需保证圆心不位于切线的延长线上，否则返回失败；
        ///    圆心与起点的连线，向切线的垂线上投影可得到一投影点，该投影点即为实际圆心；
        ///    实际圆心和起点连线确定半径长度；终点与实际圆心连线，该连线（延伸线）与圆弧的交点即为圆弧实际终点；
        /// 3、圆心与两点圆弧arcPoints+半径（isSmooth:false;useRadius:true;useAngle:false）
        ///    需保证三点arcPoints不共线，否则返回失败；
        ///    按照起点指向圆心的方向，取半径长度大小的直线确定实际圆心；
        ///    终点与实际圆心连线，该连线（延伸线）与圆弧的交点即为圆弧实际终点；
        /// 4、圆心与两点圆弧arcPoints+圆心角（isSmooth:false;useRadius:false;useAngle:true）
        ///    需保证三点arcPoints不共线，否则返回失败；
        ///    该圆心为实际圆心；终点用于确定圆弧所在平面；按照所输入的角度和弧顺逆方向，从起点开始，截取圆心角所对应的圆弧；
        /// 5、圆心与两点圆弧arcPoints+平滑+半径（isSmooth:true;useRadius:true;useAngle:false）
        ///    isCounterClock失效，需保证圆心不位于切线的延长线上，否则返回失败；
        ///    圆心用于确定实际圆心位于切线的某一侧，按照起点指向圆心的方向，取半径长度大小的直线确定实际圆心；
        ///    终点与实际圆心连线，该连线（延伸线）与圆弧的交点即为圆弧实际终点；
        /// 6、圆心与两点圆弧arcPoints+平滑+圆心角（isSmooth:true;useRadius:false;useAngle:true）
        ///    isCounterClock失效，终点失效，需保证圆心不位于切线的延长线上，否则返回失败；
        ///    圆心与起点的连线，向切线的垂线上投影可得到一投影点，该投影点即为实际圆心；
        ///    按照所输入的角度，从起点开始（弧顺逆方向由切向方向确定），截取圆心角所对应的圆弧；
        /// 7、圆心与两点圆弧arcPoints+半径+圆心角（isSmooth:false;useRadius:true;useAngle:true）
        ///    需保证三点arcPoints不共线，否则返回失败；
        ///    按照起点指向圆心的方向，取半径长度大小的直线确定实际圆心；终点用于确定圆弧所在平面；
        ///    按照所输入的角度和弧顺逆方向，从起点开始，截取圆心角所对应的圆弧；
        /// 8、圆心与两点圆弧arcPoints+平滑+半径+圆心角（isSmooth:true;useRadius:true;useAngle:true）
        ///    isCounterClock失效，终点失效，需保证圆心不位于切线的延长线上，否则返回失败；
        ///    圆心用于确定实际圆心位于切线的某一侧，按照起点指向圆心的方向，取半径长度大小的直线确定实际圆心；
        ///    按照所输入的角度，从起点开始（弧顺逆方向由切向方向确定），截取圆心角所对应的圆弧；
        /// \param[in]  arcPoints  输入为三点，分别为起点、圆心、终点
        /// \param[in]  isCounterClock  是否逆时针
        /// \param[in]  isSmooth  是否平滑连接
        /// \param[in]  useRadius  是否使用半径
        /// \param[in]  radius  圆弧半径，useRadius为true时使用（使用时半径需要大于0）
        /// \param[in]  useAngle  是否使用角度
        /// \param[in]  angle  圆弧角度，单位弧度，useAngle为true时使用（使用时需要在(0,2PI]区间内）
        /// \return  是否添加圆心端点圆弧曲线成功,成功返回true,否则返回false
        GCMP_DEPRECATED_API(2023 / 12 / 01) virtual bool AddCenterArc(const std::vector<Vector3d>& arcPoints, bool isCounterClock, bool isSmooth,
            bool useRadius, double radius, bool useAngle, double angle) = 0;

        /// \brief 向多段线中添加一条 Bezier 曲线，接口暂时未被使用，后面根据需要再放开，目前仅内部测试命令使用
        /// \param[in]  start  起点，多段线为第一条曲线有效，非第一条曲线并且isSmooth为false有效
        /// \param[in]  startTangent  起点切向，多段线为第一条曲线有效，非第一条曲线并且isSmooth为false有效
        /// \param[in]  end  终点
        /// \param[in]  endTangent  终点切向
        /// \param[in]  isSmooth  是否平滑连接，当三维多段线为空时，isSmooth失效；
        ///                       当isSmooth有效并为true时，仅使用终点和终点切向，以多段线最后一条曲线的终点为起点，并与之相切
        /// \return  是否添加 Bezier 曲线成功,成功返回true,否则返回false
        GCMP_DEPRECATED_API(2023 / 12 / 01) virtual bool AddBezier(const Vector3d& start, const Vector3d& startTangent, const Vector3d& end, const Vector3d& endTangent, bool isSmooth) = 0;

    public:
        virtual ~IPolyCurve3d() {}
    };
}
